package org.uma.jmetal.example.multiobjective.smpsorp;

import org.uma.jmetal.algorithm.multiobjective.smpso.SMPSORP;
import org.uma.jmetal.component.evaluation.Evaluation;
import org.uma.jmetal.component.evaluation.impl.SequentialEvaluation;
import org.uma.jmetal.component.termination.Termination;
import org.uma.jmetal.component.termination.impl.TerminationByEvaluations;
import org.uma.jmetal.operator.mutation.MutationOperator;
import org.uma.jmetal.operator.mutation.impl.PolynomialMutation;
import org.uma.jmetal.problem.doubleproblem.DoubleProblem;
import org.uma.jmetal.solution.doublesolution.DoubleSolution;
import org.uma.jmetal.util.JMetalException;
import org.uma.jmetal.util.JMetalLogger;
import org.uma.jmetal.util.ProblemUtils;
import org.uma.jmetal.util.archivewithreferencepoint.ArchiveWithReferencePoint;
import org.uma.jmetal.util.archivewithreferencepoint.impl.CrowdingDistanceArchiveWithReferencePoint;
import org.uma.jmetal.util.fileoutput.SolutionListOutput;
import org.uma.jmetal.util.fileoutput.impl.DefaultFileOutputContext;
import org.uma.jmetal.util.observer.impl.EvaluationObserver;
import org.uma.jmetal.util.observer.impl.RunTimeChartObserver;

import java.util.ArrayList;
import java.util.List;

public class SMPSORPWithMultipleReferencePointsAndRealTimeChartExample {
  /**
   *使用一个参考点运行SMPSORP算法的程序。 SMPSORP在
   *“使用基于参考点的首选项扩展速度受限的多目标PSO（SMPSO）
   * *发音。 Antonio J. Nebro，Juan J. Durillo，JoséGarcía-Nieto，CristóbalBarba-González，
   * *哈维尔·德尔·瑟（Javier Del Ser），卡洛斯·A·科洛·科洛（Carlos A.Coello Coello），安东尼奥·贝尼特斯·希达戈（AntonioBenítez-Hidalgo），何塞·F·阿尔达娜·蒙特斯（JoséF.Aldana-Montes）。
   * *从自然界并行解决问题-PPSN XV。 计算机科学讲义，第1卷。 11101，
   * *第298-310页。 2018年
   *
   * @author Antonio J. Nebro
   */
  public static void main(String[] args) throws JMetalException {
    DoubleProblem problem;
    SMPSORP algorithm;
    MutationOperator<DoubleSolution> mutation;

    String problemName = "org.uma.jmetal.problem.multiobjective.zdt.ZDT1";
    String referenceParetoFront = "resources/referenceFrontsCSV/ZDT1.csv";

    problem = (DoubleProblem) ProblemUtils.<DoubleSolution>loadProblem(problemName);

    List<List<Double>> referencePoints;
    referencePoints = new ArrayList<>();
    referencePoints.add(List.of(0.2, 0.8));
    referencePoints.add(List.of(0.7, 0.4));

    double mutationProbability = 1.0 / problem.getNumberOfVariables();
    double mutationDistributionIndex = 20.0;
    mutation = new PolynomialMutation(mutationProbability, mutationDistributionIndex);

    int maxEvaluations = 25000;
    int swarmSize = 100;

    List<ArchiveWithReferencePoint<DoubleSolution>> archivesWithReferencePoints = new ArrayList<>();

    for (int i = 0; i < referencePoints.size(); i++) {
      archivesWithReferencePoints.add(
              new CrowdingDistanceArchiveWithReferencePoint<DoubleSolution>(
                      swarmSize / referencePoints.size(), referencePoints.get(i)));
    }

    Evaluation<DoubleSolution> evaluation = new SequentialEvaluation<>(problem);
    Termination termination = new TerminationByEvaluations(maxEvaluations);

    algorithm = new SMPSORP(problem,
            swarmSize,
            archivesWithReferencePoints,
            referencePoints,
            mutation,
            0.0, 1.0,
            0.0, 1.0,
            2.5, 1.5,
            2.5, 1.5,
            0.1, 0.1,
            -1.0, -1.0,
            evaluation, termination);

    var evaluationObserver = new EvaluationObserver(100);
    var runTimeChartObserver = new RunTimeChartObserver<>("SMPSORP", 80, referenceParetoFront);
    runTimeChartObserver.setReferencePointList(referencePoints);

    algorithm.getObservable().register(evaluationObserver);
    algorithm.getObservable().register(runTimeChartObserver);

    algorithm.run();

    JMetalLogger.logger.info("Total execution time : " + algorithm.getTotalComputingTime() + "ms");
    JMetalLogger.logger.info("Number of evaluations: " + algorithm.getEvaluations());

    new SolutionListOutput(algorithm.getResult())
            .setVarFileOutputContext(new DefaultFileOutputContext("VAR.csv", ","))
            .setFunFileOutputContext(new DefaultFileOutputContext("FUN.csv", ","))
            .print();

    System.exit(0);
  }
}
